/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2025 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "usb_device.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "usbd_hid.h"
#include <string.h>

/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
#define DOT_BUTTON_PORT GPIOC
#define DOT_BUTTON_PIN GPIO_PIN_8
#define DASH_BUTTON_PORT GPIOC
#define DASH_BUTTON_PIN GPIO_PIN_9
#define CONFIRM_BUTTON_PORT GPIOA
#define CONFIRM_BUTTON_PIN GPIO_PIN_0

#define DOT_BUTTON_PRESSED GPIO_PIN_RESET  // PC8按键按下时为低电平
#define DASH_BUTTON_PRESSED GPIO_PIN_RESET  // PC9按键按下时为低电平
#define CONFIRM_BUTTON_PRESSED GPIO_PIN_SET   // PA0按键按下时为高电平(3.3V)

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
extern USBD_HandleTypeDef hUsbDeviceFS;
uint8_t morse_buffer[100];    // 存储摩斯密码
uint8_t morse_index = 0;      // 摩斯密码索引

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
void SendSingleKey(uint8_t key);
uint8_t MorseToKey(uint8_t* morse_code, uint8_t length);
void ClearMorseBuffer(void);
void AddMorseSymbol(char symbol);
void ProcessAndSendMorse(void);

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/**
  * @brief  发送单个按键
  * @param  key: 按键码
  * @retval None
  */
void SendSingleKey(uint8_t key)
{
    uint8_t key_report[8] = {0};
    
    // 按下按键
    key_report[2] = key;
    USBD_HID_SendReport(&hUsbDeviceFS, key_report, 8);
    HAL_Delay(20);
    
    // 释放按键
    memset(key_report, 0, 8);
    USBD_HID_SendReport(&hUsbDeviceFS, key_report, 8);
    HAL_Delay(20);
}

/**
  * @brief  将摩斯密码转换为对应的按键码
  * @param  morse_code: 摩斯密码数组
  * @param  length: 摩斯密码长度
  * @retval 按键码 (0表示未找到匹配)
  */
uint8_t MorseToKey(uint8_t* morse_code, uint8_t length)
{
    // 定义字母A-Z的摩斯密码
    const char* morse_table[] = {
        ".-", "-...", "-.-.", "-..", ".", "..-.", "--.", "....", "..", // A-I
        ".---", "-.-", ".-..", "--", "-.", "---", ".--.", "--.-", ".-.", // J-R
        "...", "-", "..-", "...-", ".--", "-..-", "-.--", "--.."        // S-Z
    };
    
    // 检查每个字母
    for(int i = 0; i < 26; i++)
    {
        uint8_t match = 1;
        const char* table_morse = morse_table[i];
        uint8_t table_length = strlen((char*)table_morse);
        
        // 长度必须匹配
        if(table_length != length)
            continue;
            
        // 逐个字符比较
        for(int j = 0; j < length; j++)
        {
            if(morse_code[j] != table_morse[j])
            {
                match = 0;
                break;
            }
        }
        
        if(match)
            return 0x04 + i; // A=0x04, B=0x05, ...
    }
    
    return 0; // 未找到匹配
}

/**
  * @brief  清空摩斯密码缓冲区
  * @retval None
  */
void ClearMorseBuffer(void)
{
    memset(morse_buffer, 0, sizeof(morse_buffer));
    morse_index = 0;
}

/**
  * @brief  添加摩斯符号到缓冲区
  * @param  symbol: 符号('.' 或 '-')
  * @retval None
  */
void AddMorseSymbol(char symbol)
{
    if(morse_index < sizeof(morse_buffer) - 1)
    {
        morse_buffer[morse_index] = symbol;
        morse_index++;
        
        // LED指示
        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_RESET);
        if(symbol == '.')
        {
            HAL_Delay(100);
        }
        else
        {
            HAL_Delay(400);
        }
        HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_SET);
        HAL_Delay(100);
    }
}

/**
  * @brief  处理摩斯密码输入并发送
  * @retval None
  */
void ProcessAndSendMorse(void)
{
    if(morse_index > 0)
    {
        // 尝试解析摩斯密码
        uint8_t key = MorseToKey(morse_buffer, morse_index);
        if(key != 0)
        {
            SendSingleKey(key);
            
            // LED指示成功发送
            for(int i = 0; i < 3; i++)
            {
                HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_RESET);
                HAL_Delay(100);
                HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_SET);
                HAL_Delay(100);
            }
        }
        else
        {
            // LED指示错误
            for(int i = 0; i < 5; i++)
            {
                HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_RESET);
                HAL_Delay(50);
                HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_SET);
                HAL_Delay(50);
            }
        }
        
        // 清空缓冲区
        ClearMorseBuffer();
    }
}

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
    /* USER CODE BEGIN 1 */
    
    /* USER CODE END 1 */
    
    /* MCU Configuration--------------------------------------------------------*/
    
    /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
    HAL_Init();
    
    /* USER CODE BEGIN Init */
    
    /* USER CODE END Init */
    
    /* Configure the system clock */
    SystemClock_Config();
    
    /* USER CODE BEGIN SysInit */
    
    /* USER CODE END SysInit */
    
    /* Initialize all configured peripherals */
    MX_GPIO_Init();
    MX_USB_DEVICE_Init();
    
    /* USER CODE BEGIN 2 */
    
    // 等待USB稳定
    HAL_Delay(1000);
    
    // 初始化LED
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_SET);
    
    /* USER CODE END 2 */
    
    /* Infinite loop */
    /* USER CODE BEGIN WHILE */
    while (1)
    {
        /* USER CODE END WHILE */
        
        /* USER CODE BEGIN 3 */
        
        // 检查点按钮(PC8)
        if(HAL_GPIO_ReadPin(DOT_BUTTON_PORT, DOT_BUTTON_PIN) == DOT_BUTTON_PRESSED)
        {
            // 防抖延时
            HAL_Delay(50);
            if(HAL_GPIO_ReadPin(DOT_BUTTON_PORT, DOT_BUTTON_PIN) == DOT_BUTTON_PRESSED)
            {
                // 记录点
                AddMorseSymbol('.');
                
                // 等待按键释放
                while(HAL_GPIO_ReadPin(DOT_BUTTON_PORT, DOT_BUTTON_PIN) == DOT_BUTTON_PRESSED)
                {
                    HAL_Delay(10);
                }
                HAL_Delay(50); // 防抖
            }
        }
        // 只有在点按钮未按下时才检查划按钮，避免冲突
        else if(HAL_GPIO_ReadPin(DASH_BUTTON_PORT, DASH_BUTTON_PIN) == DASH_BUTTON_PRESSED)
        {
            // 防抖延时
            HAL_Delay(50);
            if(HAL_GPIO_ReadPin(DASH_BUTTON_PORT, DASH_BUTTON_PIN) == DASH_BUTTON_PRESSED)
            {
                // 记录划
                AddMorseSymbol('-');
                
                // 等待按键释放
                while(HAL_GPIO_ReadPin(DASH_BUTTON_PORT, DASH_BUTTON_PIN) == DASH_BUTTON_PRESSED)
                {
                    HAL_Delay(10);
                }
                HAL_Delay(50); // 防抖
            }
        }
        // 只有在点划按钮都未按下时才检查确认按钮，避免冲突
        else if(HAL_GPIO_ReadPin(CONFIRM_BUTTON_PORT, CONFIRM_BUTTON_PIN) == CONFIRM_BUTTON_PRESSED)
        {
            // 防抖延时
            HAL_Delay(50);
            if(HAL_GPIO_ReadPin(CONFIRM_BUTTON_PORT, CONFIRM_BUTTON_PIN) == CONFIRM_BUTTON_PRESSED)
            {
                // 处理并发送摩斯密码
                ProcessAndSendMorse();
                
                // 等待按键释放
                while(HAL_GPIO_ReadPin(CONFIRM_BUTTON_PORT, CONFIRM_BUTTON_PIN) == CONFIRM_BUTTON_PRESSED)
                {
                    HAL_Delay(10);
                }
                HAL_Delay(50); // 防抖
            }
        }
        
        HAL_Delay(10);
    }
    /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
    RCC_OscInitTypeDef RCC_OscInitStruct = {0};
    RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
    RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
    
    /** Initializes the RCC Oscillators according to the specified parameters
    * in the RCC_OscInitTypeDef structure.
    */
    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
    RCC_OscInitStruct.HSEState = RCC_HSE_ON;
    RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
    RCC_OscInitStruct.HSIState = RCC_HSI_ON;
    RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
    RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
    RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
    if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
    {
        Error_Handler();
    }
    
    /** Initializes the CPU, AHB and APB buses clocks
    */
    RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                                |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
    RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
    RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
    RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
    RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
    
    if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
    {
        Error_Handler();
    }
    PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USB;
    PeriphClkInit.UsbClockSelection = RCC_USBCLKSOURCE_PLL_DIV1_5;
    if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
    {
        Error_Handler();
    }
}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
    /* USER CODE BEGIN Error_Handler_Debug */
    /* User can add his own implementation to report the HAL error return state */
    __disable_irq();
    while (1)
    {
    }
    /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
    /* USER CODE BEGIN 6 */
    /* User can add his own implementation to report the file name and line number,
       ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
    /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */